using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace IRCEngine
{
	public sealed class Message : MarshalByRefObject
	{
		private static readonly String[] emptyArray = new String[0];

		public Prefix Prefix { get; private set; }
		public Command Command { get; private set; }
		public Params Params { get; private set; }
		public string Original { get; private set; }

		public Message(String line)
		{
			Original = line;
			int position = 0;
			int delim;
			if (line == null)
				return;
			if (line.Length == 0)
				return;
			if (line[position] == ':')
			{
				delim = line.IndexOf(' ', position);
				Prefix = new Prefix(line.Substring(position + 1, delim - position - 1));
				delim++;
				while ((delim < line.Length) && (line[delim] == ' '))
					delim++;
				position = delim;
			}
			if (line.Length <= position)
				return;
			delim = line.IndexOf(' ', position);
			if (delim == -1)
				delim = line.Length;
			Command = new Command(line.Substring(position, delim - position));
			delim++;
			while ((delim < line.Length) && (line[delim] == ' '))
				delim++;
			position = delim;
			if (line.Length > position)
				Params = new Params(line.Substring(position));
		}

		private static String BuildLine(String prefix, String command, params String[] parameters)
		{
			return BuildLine(prefix, command, false, parameters);
		}

		private static String BuildLine(String prefix, String command, bool forceLastAsTrailing, params String[] parameters)
		{
			StringBuilder sb = new StringBuilder();
			if ((prefix != null) && (prefix.Length > 0))
			{
				sb.Append(':').Append(prefix).Append(' ');
			}
			sb.Append(command);
			int last = parameters.Length;
			if (forceLastAsTrailing)
				last--;
			int i;
			for (i = 0; i < last; i++)
			{
				if (parameters[i].IndexOf(' ') >= 0)
					break;
				sb.Append(' ').Append(parameters[i]);
			}
			if (i < parameters.Length)
			{
				sb.Append(" :");
			}
			for (; i < parameters.Length; i++)
			{
				sb.Append(parameters[i]);
			}
			sb.Append("\r\n");
			return sb.ToString();
		}

		public static string BuildNickMessage(String nick)
		{
			return BuildLine(null, "NICK", nick);
		}

		public static string BuildUserMessage(String user, int mode, string realName)
		{
			return BuildLine(null, "USER", true, user, mode.ToString(), "*", realName);
		}

		public static string BuildQuitMessage(String quitMessage)
		{
			return BuildLine(null, "QUIT", true, quitMessage);
		}

		public static string BuildJoinMessage(String channel)
		{
			return BuildLine(null, "JOIN", true, channel);
		}

		public static string BuildPartMessage(String channel)
		{
			return BuildLine(null, "PART", true, channel);
		}

		private static string BuildLowLevelMessage(string command, string chanOrUser, string text)
		{
			return BuildLine(null, command, true, chanOrUser, MessageConverter.LowLevelEncode(text));
		}

		public static string BuildPrivMsgMessage(String chanOrUser, String text)
		{
			return BuildLowLevelMessage("PRIVMSG", chanOrUser, MessageConverter.CTCPEncode(text));
		}

		public static string BuildNoticeMessage(String chanOrUser, String text)
		{
			return BuildLowLevelMessage("NOTICE", chanOrUser, MessageConverter.CTCPEncode(text));
		}

		public static string BuildActionMessage(String chanOrUser, String text)
		{
			return BuildCTCPRequest(chanOrUser, "ACTION " + text);
		}

		public static string BuildCTCPRequest(String chanOrUser, String text)
		{
			return BuildLowLevelMessage("PRIVMSG", chanOrUser, MessageConverter.CTCPTag(text));
		}

		public static string BuildCTCPReply(String chanOrUser, String text)
		{
			return BuildLowLevelMessage("NOTICE", chanOrUser, MessageConverter.CTCPTag(text));
		}

		public static string BuildPongMessage(String param1)
		{
			return BuildLine(null, "PONG", param1);
		}

		public static string BuildPongMessage(String param1, String param2)
		{
			return BuildLine(null, "PONG", param1, param2);
		}
	}
}
